package com.jie.algorithm.algorithm;

import android.annotation.SuppressLint;
import android.util.Log;

import com.blankj.utilcode.util.ToastUtils;
import com.jie.algorithm.ui.main.MainBean;
import com.jie.commonlib.support.eventbus.EventBusManager;
import com.jie.commonlib.support.eventbus.EventConstant;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableEmitter;
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;


/**
 * 算法执行工具类
 * 参考资料：https://www.cnblogs.com/onepixel/articles/7674659.html
 * @author jie
 */
public class AlgorithmUtils {

    private static final String TAG = "AlgorithmUtils";
    private static Disposable mDisposable;
    /**
     * 判断是否正在执行
     */
    private static boolean doing = false;

    /**
     * 通过排序算法值转换为中文值
     *
     * @param value
     */
    public static String getAlgorithmName(int value) {
        AlgorithmEnum[] algorithmEnums = AlgorithmEnum.values();
        for (AlgorithmEnum algorithmEnum : algorithmEnums) {
            if (algorithmEnum.id == value) {
                return algorithmEnum.name;
            }
        }
        return AlgorithmEnum.SORT_BUBBLING.name;
    }

    /**
     * 执行算法
     *
     * @param list      需要排序的算法集合
     * @param algorithm 算法类型
     */
    public static void doAlgorithm(final ArrayList list, final int algorithm) {
        if (list == null || list.isEmpty()) {
            return;
        }
        if (doing){
            ToastUtils.showShort("算法执行中，请稍后...");
            return;
        }
        doing = true;
        Observable
                .create(new ObservableOnSubscribe<List<MainBean>>() {
                    @Override
                    public void subscribe(ObservableEmitter<List<MainBean>> e) throws Exception {
                        if (algorithm == AlgorithmEnum.SORT_BUBBLING.id) {
                            doBubbling(e, list);
                        } else if (algorithm == AlgorithmEnum.SORT_CHOICE.id) {
                            doChoice(e, list);
                        } else if (algorithm == AlgorithmEnum.SORT_INSET.id) {
                            doInset(e, list);
                        } else if (algorithm == AlgorithmEnum.SORT_SHELL.id) {
                            doShell(e, list);
                        } else if (algorithm == AlgorithmEnum.SORT_MERGE.id) {
                            doMerge(e, list, 0, list.size() - 1);
                            e.onComplete();
                        }
                    }
                })
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<List<MainBean>>() {
                    // 记录算法开始时间
                    private long startTime = 0;

                    @Override
                    public void onSubscribe(Disposable d) {
                        startTime = System.currentTimeMillis();
                        mDisposable = d;
                    }

                    @Override
                    public void onNext(List<MainBean> list) {
                        Log.i(TAG, "onNext: " + list.size());
                        EventBusManager.getInstance().sendEvent(EventConstant.CODE_ALGORITHM_OVER);
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.i(TAG, "onError: " + e);
                        doing = false;
                    }

                    @SuppressLint("RestrictedApi")
                    @Override
                    public void onComplete() {
                        long totalTime = System.currentTimeMillis() - startTime;
                        StringBuilder result = new StringBuilder();
                        androidx.core.util.TimeUtils.formatDuration(totalTime, result);
                        Log.i(TAG, "onComplete: 算法执行时间" + result + Thread.currentThread().getName());
                        doing = false;
                        ToastUtils.showShort("算法执行完毕");
                    }
                });

    }

    /**
     * 取消算法任务订阅
     */
    public static void cancel(){
        doing = false;
        if (mDisposable != null){
            mDisposable.dispose();
        }
    }

    /**
     * 执行冒泡排序
     */
    private static void doBubbling(ObservableEmitter<List<MainBean>> e, List<MainBean> list) throws InterruptedException {
        int size = list.size();
        if (size <= 1) {
            return;
        }
        for (int i = 0; i < size - 1; i++) {
            for (int j = 0; j < size - i - 1; j++) {
                MainBean bean1 = list.get(j);
                MainBean bean2 = list.get(j + 1);
                if (bean1.getHeight() > bean2.getHeight()) {
                    Collections.swap(list, j, j + 1);
                    e.onNext(list);
                    Thread.sleep(10);
                }
            }
        }
        e.onComplete();
    }

    /**
     * 执行选择排序
     */
    private static void doChoice(ObservableEmitter<List<MainBean>> e, List<MainBean> list) throws InterruptedException {
        int size = list.size();
        if (size <= 1) {
            return;
        }
        int minIndex;
        for (int i = 0; i < size - 1; i++) {
            minIndex = i;
            for (int j = i + 1; j < size; j++) {
                MainBean mainBean1 = list.get(j);
                MainBean mainBean2 = list.get(minIndex);
                if (mainBean1.getHeight() < mainBean2.getHeight()) {
                    minIndex = j;
                }
            }
            if (minIndex > i) {
                Collections.swap(list, i, minIndex);
                e.onNext(list);
                Thread.sleep(10);
            }
        }
        e.onComplete();
    }

    /**
     * 执行插入排序
     */
    private static void doInset(ObservableEmitter<List<MainBean>> e, List<MainBean> list) throws InterruptedException {
        int size = list.size();
        if (size <= 1) {
            return;
        }
        for (int i = 1; i < size; i++) {
            MainBean mainBean1 = list.get(i);
            for (int j = i - 1; j >= 0; j--) {
                MainBean mainBean2 = list.get(j);
                if (mainBean1.getHeight() < mainBean2.getHeight()) {
                    Collections.swap(list, j, j + 1);
                    e.onNext(list);
                    Thread.sleep(10);
                } else {
                    break;
                }
            }
        }
        e.onComplete();
    }

    /**
     * 执行希尔排序
     */
    private static void doShell(ObservableEmitter<List<MainBean>> e, List<MainBean> list) throws InterruptedException {
        int size = list.size();
        if (size <= 1) {
            return;
        }
        // 当i == 1时应直接跳出循环，不然会造成死循环
        for (int i = size / 3 + 1; i >= 1; i = i == 1 ? 0 : i / 3 + 1) {
            for (int j = i; j < size; j++) {
                MainBean mainBean1 = list.get(j);
                for (int k = j - i; k >= 0; k -= i) {
                    MainBean mainBean2 = list.get(k);
                    if (mainBean1.getHeight() < mainBean2.getHeight()) {
                        Collections.swap(list, k, k + i);
                        e.onNext(list);
                        Thread.sleep(10);
                    } else {
                        break;
                    }
                }
            }
        }
        e.onComplete();
    }

    /**
     * 执行归并排序
     * 递归调用
     */
    private static void doMerge(ObservableEmitter<List<MainBean>> e, List<MainBean> list, int left, int right) throws InterruptedException {
        if (left >= right) {
            // 跳出递归调用
            return;
        }
        // 找到中间位置
        int middle = (left + right) / 2;
        // 对左边子序列进行递归归并排序
        doMerge(e,list, left, middle);
        // 对右边子序列进行递归归并排序
        doMerge(e,list, middle + 1, right);
        // 进行归并
        doMerge(e, list, left, middle, right);
    }

    /**
     * 执行归并排序
     * 递归调用
     */
    private static void doMerge(ObservableEmitter<List<MainBean>> e, List<MainBean> list, int left, int mid, int right) throws InterruptedException {
        MainBean[] tempArr = new MainBean[list.size()];
        int leftStart = left;
        int rightStart = mid+1;
        int tempIndex = left;

        while(leftStart <= mid && rightStart <= right) {
            MainBean leftItem = list.get(leftStart);
            MainBean rightItem = list.get(rightStart);
            if(leftItem.getHeight() < rightItem.getHeight()) {
                tempArr[tempIndex] = leftItem;
                leftStart ++;
            } else {
                tempArr[tempIndex] = rightItem;
                rightStart ++;
            }
            tempIndex ++;
        }

        while(leftStart <= mid) {
            // 左边有多，直接加到后面
            tempArr[tempIndex] = list.get(leftStart);
            tempIndex ++;
            leftStart ++;
        }

        while(rightStart <= right) {
            // 右边有多，也直接加到后面
            tempArr[tempIndex] = list.get(rightStart);
            tempIndex ++;
            rightStart ++;
        }

        while(left <= right) {
            // 将临时集合中的数据设置到原集合中
            list.set(left, tempArr[left]);
            left ++;
        }
        e.onNext(list);
        Thread.sleep(10);
    }

}
